﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Ewk.Runtime.Serialization
{
    /// <summary>
    /// Contains information about the datarecord that has a <see cref="DatarecordAttribute"/> on it.
    /// </summary>
    /// <typeparam name="T">The <see cref="Type"/> of the datarecord.</typeparam>
    class DatarecordInfo<T>
    {
        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        public DatarecordInfo()
        {
            // Get the DatarecordAttributes
            DatarecordAttribute = typeof(T).GetCustomAttributes(typeof(DatarecordAttribute), true).SingleOrDefault() as DatarecordAttribute;
            if (DatarecordAttribute == null)
            {
                throw new DatarecordNotDefinedException();
            }

            // Get the properties with DatafieldAttributes
            var fields = typeof(T).FindMembers(MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, PropertyHasDatafieldAttribute, null);
            if (fields.Length == 0)
            {
                var exceptionMessage = string.Format(CultureInfo.CurrentCulture, ExceptionMessages.DatarecordWithoutDatafields, typeof(T));
                throw new DatarecordWithoutDatafieldsException(exceptionMessage);
            }

            var datafieldAttributes = new List<DatafieldAttribute>();
            foreach (var memberInfo in fields)
            {
                var attribute = (DatafieldAttribute)memberInfo.GetCustomAttributes(typeof(DatafieldAttribute), true).Single();
                attribute.PropertyInfo = (PropertyInfo)memberInfo;
                datafieldAttributes.Add(attribute);
            }

            DatafieldAttributes = DatarecordAttribute.PrepareDatafieldAttributes(datafieldAttributes).AsParallel();
        }

        /// <summary>
        /// Gets the <see cref="DatarecordAttribute">attribute that is defined on the record.</see>
        /// </summary>
        public DatarecordAttribute DatarecordAttribute { get; private set; }

        /// <summary>
        /// Gets a list of <see cref="DatafieldAttribute"/> that contain information about the properties of the datarecord.
        /// </summary>
        public ParallelQuery<DatafieldAttribute> DatafieldAttributes { get; private set; }

        static bool PropertyHasDatafieldAttribute(MemberInfo info, object member)
        {
            return info.GetCustomAttributes(typeof(DatafieldAttribute), true).Length > 0;
        }
    }
}
